home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_100 / 130_01 / bs.use < prev    next >
Text File  |  1985-03-09  |  9KB  |  156 lines

  1.     Bs.use, a tutorial on the use of the binary search file functions.
  2.  
  3.     The functions and their calling syntax are described in ry.doc.  They
  4. use the random file functions of ry and the 'long int' code of long.c.  The
  5. file 'lx.crl' contains the functions from long.c, plus several required
  6. additional functions.  This code also has the limitation of all ry code in that
  7. it needs a z-80 machine to run.
  8.  
  9.     Bs.c consists of functions to manipulate files of records sorted with a
  10. binary insertion algorithm.  The creation of a 'bs' file actually creates 2
  11. files.  One is a block of integer pointers to records in a second file.  As
  12. records are added/deleted from the second file, the pointers in the first are
  13. modified accordingly.  The first file is kept in core while the files are open,
  14. and returned to disk when closed.  The records can be of almost any format that
  15. is convenient to the using program.  The only restriction is that the key must
  16. be the first item of a record and that the record has to be a consistant size
  17. throughout the file. (note - these functions have only been used with string
  18. keys to date, I suspect that there may be a bug or two with other type keys)
  19.  
  20.     The comparison used to sort the keys is passed as a pointer to a
  21. comparison function, declared in the file open statement.  This allows a great
  22. deal of flexability in setting up record types.  For instance, most files will
  23. be setup on ascii string keyed records.  The standard string comparison
  24. function will return unequal for upper/lower case differences.  A comparison
  25. function that ignores case differences could be written, allowing its use to
  26. index strings as equal if chars are the same, even though in different case.
  27.  
  28.     As records are removed from the file the storage they use is returned
  29. to a free list, keeping a highly dynamic file from getting unreasonably large.
  30. The maximum number of elements kept in a file must be specified at file
  31. creation time (bsmake()).  Since the pointer file is kept in core the maximum
  32. number will most likely be limited by the size of core as oppossed to the disk
  33. space.  Even so, each pointer needing two bytes, most systems should be able to
  34. handle files of 5,000 records or more (depending of course on the memory needed
  35. by the rest of the program).
  36.  
  37.     The primary functions include:
  38.  
  39.     1: bsmake(), to creat a file set (pointer file and data file).
  40.     2: bsopen(), to open a file (bsmake only creates a file, doesn't open).
  41.     3: bswrite(), write a record to file according to sort order specified
  42.         by the comparison function declared at open.
  43.     4: bsread(), read a record from file if found, else returns 'BELONGS'.
  44.     5: bssearch(), searches for a file by the specified key, returns
  45.         'FOUND', 'BELONGS', (or possibly ERROR).
  46.     6: bsclose(), flushes buffers, closes files.
  47.     7: bskey_rmv(), removes the record from the file.
  48.  
  49.     There are also several lowlevel functions called by the above, but
  50. these are not usually of concern to the user.
  51.  
  52.     First an example of the creation of a file set:
  53.  
  54.     bsmake("datafile", "pointerfile", data_size, max_records);
  55.  
  56.     "datafile" is any legal file name, it will be the file that holds the
  57. actual records.  "pointer_file" would be a legal file name, it will hold the
  58. pointers.  "datafile" will be created as a random file using ry functions, most
  59. notably the 'bseek()' and 'btell()' functions.  These are functions that do
  60. block seeks and reports, using a set record size.  "pointer_file" is created
  61. using the raw file functions, it is swapped into core when the file is opened
  62. and swapped back to disk when closed.  'bsmake()' only creats and initializes
  63. as empty the file set, you still have to open them to use them.  Data_size is
  64. the size of a record in bytes, and max_records is the maximum number of records
  65. that the file will hold (remember above discussion of maximum records in a
  66. file). 
  67.  
  68.     First we declare a pointer to a structure of type _bs:
  69.  
  70.     BSFILE *bs;
  71.  
  72.         (note - BSFILE is #defined as 'struct _bs' in ry.h)
  73.  
  74.     We open the file, saving the result in our file pointer:
  75.  
  76.     int key_comp();        /* declare compare funct */
  77.  
  78.     bs = bsopen("foo.dat", "foo.ptr", key_comp, sectors);
  79.  
  80.     The first 2 strings are the data file and pointer file names.  Key_comp
  81. is a pointer to a function that compares the keys in the manner that we wish.
  82. It typically will be the function 'strcmp()' from the standard library.  The
  83. only necessary conditions for custom comparison functions is that they return 0
  84. for TRUE compare, <1 for key 1 less than key 2, and >1 for key 1 greater than
  85. key 2.  Page 101 of K&R gives a complete description of what is necessary here.
  86. Sectors is a declaration of the number of logical sectors to use for buffering.
  87. Its value would depend on how precious memory is, but typically would be 8 (or
  88. whatever multiple of logical sectors is contained in a physical sector on your
  89. system).  The same considerations in choosing buffer size of random files apply
  90. here.  Bs is now used to describe the file in all reads, writes, and searches
  91.  
  92.     To add a keyed record to the file:
  93.  
  94.     result = bswrite(bs, key, address);
  95.  
  96.     Bs is the pointer returned by the open.  Key is the key that we want
  97. the record to be added by.  This key must also be the first item in the record.
  98. Address is the address in memory where the record (including leading key) is
  99. contained.  If key[0] is NULL the record is written at the point in the file
  100. last found by a 'bssearch()'.  If it contains a key 'bssearch()' is called by
  101. 'bswrite()' first to find the appropriate record.  This allows us to look for
  102. an existing record, and depending on whether or not it does exist, decide to do
  103. the write.  To clarify, we might not want to write a record if it already
  104. exists.  By doing a search first we could abort if it exists.  If not, we could
  105. write it without causing 'bswrite()' to call search again by passing a NULL
  106. string as the key, thus saving considerable time.  In the case of a non-keyed
  107. write 'BELONGS' is returned if the record didn't exist prior to the write while
  108. 'FOUND' will be returned if the record existed and is overwritten.  When a
  109. keyed record write is specified 'OK' will be returned if all goes well.  ERROR
  110. will be returned on disk error in either case.
  111.  
  112.     To read a record by key:
  113.  
  114.     result = bsread(bs, key, address);
  115.  
  116.     Bs is again the pointer from 'bsopen()', key the string to look for,
  117. and address the address in memory to place the record.  If found the record is
  118. written to memory and 'FOUND' is returned.  If not found the memory at address
  119. will not be disturbed, and 'BELONGS' will be returned.  ERROR would be returned
  120. on disk error.
  121.  
  122.     To search for a keyed record:
  123.  
  124.     result = bssearch(bs, key);
  125.  
  126.     Bs being the file pointer and key, of course, the key to base the
  127. search on.  It will return 'FOUND' if it exists and set an internal pointer to
  128. the disk block containing the record.  This is to allow a non-keyed write as
  129. discussed above.  It will return 'BELONGS' if not found, again setting the
  130. internal pointer for non-keyed writes.  It might also return ERROR if disk
  131. fills up, disk ERROR occurs, etc.
  132.  
  133.     To remove a keyed record and return its storage to the free list:
  134.  
  135.     result = bskey_rmv(bs, key);
  136.  
  137.     Bs the pointer, and key the key, of course, of course (this is getting
  138. rather boring).  If the keyed record is not found but no file errors occur
  139. 'BELONGS' is returned.  If found it is removed, its storage returned to free
  140. list, and 'OK' is returned.  File error returns 'ERROR'.
  141.  
  142.  
  143.     The first block of the blocked, random file used to store the records holds
  144. info used to access the records.  Thus block 0 is reserved, if you do any
  145. internal diddling on a bs file.  Block 1 holds the first record entered into
  146. the file.  Within block 0 the first 2 bytes holds an int, the value being the
  147. number of records presently in the file.  It is set to 0 by 'bsmake()'.  The
  148. second 2 bytes hold the int value of the head of the free list.  It initially
  149. is 0, will point to a record as it is freed.  That record will then hold the
  150. pointer to next free record, or 0 if end of list, and so on.  T